var controller = {
	canvas : null,
	context : null,
	
	intro: 119,
	curIntro: -1,
	
	xSpeed : 3,
	doSin : true,
	sinOff : 90,
	
	blendMode: 1,
	blendModes: [ "source-over", "lighter", "darker", "xor" ],
	
	//1,61,96,72,92,94,18,13,33,46,4,14,131,47,0,0,0,91,167,1,40,14,129,0,187,121,215,193,32,21,208,1 : ryanmiglavs
	eg : [
		[2, 216, 30, 35, 37, 45, 25, 5,	10, 25, 16, 1.5, 61, 360, 0.5, 0, 171, 150, 250, 1, 47, 47, 42, 0, 0, 0, 35, 0, 60, 60, 60, 0, 1],
 		[2, 216, 48, 64, 113, 91, 0, 11,23, 7, 11, 1.5, 126, 54, -0.5, 0, 0, 211, 0, 0, 47, 47, 42, 0, 0, 0, 164, 252, 0, 0, 0, 0, 1],
		[2,300,45,15,10,10,  59, 10,9,7,5, 1.5,0, 360,0.2, 0.4, 250, 144, 35, 1, 32, 31, 25, 0, 245, 0, 0, 0, 21, 21, 8, 0, 1],
		[2,77,78,9,200,200,28,87,37,7,2,1.5,77,360,-0.25,0,0,51,209,5,13,25,194,85,0,199,200,249,21,21,8,0,3 ],
		[2,300,45,15,200,200,59,10,9,7,5,1.5,315,34,-1.75,1.25,0,0,0,1,255,255,255,0,0,0,0,0,255,255,236,0,1],
		[2,26,96,57,92,94,61,13,27,46,13,27,34,360,0.25,0,0,91,167,1,40,14,129,0,24,0,215,93,32,21,208,1,1]
	],
	schemaVersion : 2,
	
	init : function(){
		this.canvas = document.getElementById( "blobs" );
		if(!this.canvas.getContext){
			alert( "Sorry cobber, no Canvas support in yo' browser..." );
			return;
		}
		this.context = this.canvas.getContext( "2d" );
		this.setBlendMode( this.blendMode );
		
		this.pe = new cParticleEmitter();		
		this.pe.init();
		
		// Add the sliders
		this.addPeHandlers();
	
		// Run!
		this.main();
	},
		
	main : function(){
		this.update();
		this.draw();
		setTimeout( function(){ controller.main(); }, 100 );
	},
	
	update : function(){
		// Intro demo
		if( this.intro > 0 ){
			if( this.intro % 30 === 0 ){
				this.setExample( ++this.curIntro % ( this.eg.length ) );
			}
			if( --this.intro === 0 ){
				$( "#bounce" ).slider( "value", 0 );
			}
		}
		
		// Update the particle emitter
		this.pe.update(1);						
		
		// Bounce
		if( this.doSin ){
			// Bounce the PE around
			this.sinOff += this.xSpeed;     
		    this.sinOff = this.sinOff % 360;
			var pi180 = Math.PI / 180;
	    	this.pe.position.y  = 180 - ( Math.sin( pi180 * this.sinOff * 3 ) * 180 );
	        this.pe.position.x = 300 - ( Math.cos( pi180 * this.sinOff ) * 300 );
		}

	},
	
	draw : function(){
		this.context.clearRect( 0, 0, 690, 452 );
		this.pe.renderParticles( this.context );	 
	},
	
	/* ---- Helper functions for loading/setting slider values etc ---- */
	
	setBlendMode : function( mode ){
		this.blendMode = mode;
		this.context.globalCompositeOperation = this.blendModes[ mode >= 0 && mode < this.blendModes.length ? mode : 0 ];
	},
	
	setExample : function( index ){
		var example = $.isArray( index ) ? index : this.eg[ index ];
		if( example[ 0 ] != this.schemaVersion ){
			example = this.updateSchema( example );
		}
		$( ".ctrlSlider" ).each( function( i ){
			// Plus 1 to get rid of schema first element
			if( i + 1 <= example.length - 1 ){
				$(this).slider("value", example[ i + 1 ]);
			}
		});
	},
	
	getExample : function(){
		var exp = [];
		exp.push( controller.schemaVersion );
		$( ".ctrlSlider" ).each( function(){
			exp.push( $( this ).slider( "option", "value" ) );
		});
		return exp.join( "," );
	},
	
	loadExample: function( inp ){
		var arr = this.arrayify( inp );
		if( typeof arr === "string" ){
			alert(arr);
			return;
		}
		this.setExample( arr );
	},
	
	updateSchema: function( arr ){
		if( arr.length < 1 || arr[ 0 ] == this.schemaVersion ) return arr;
		
		// Handle "file" schema changes
		switch( arr[ 0 ] ){
			case 1:
				// Added blending mode slider
				arr.push( 1 ); // Add "lighter" to array
				arr[ 0 ] = 2; // update schema
				break;
		}
		return arr;
	},
	
	arrayify : function( str ){
		var matches = str.match(/[0-9,\.-]{20,}/);
		if(matches.length !== 1){
			return 'sorry, couldn\'t load';
		}
		var inpArray = this.updateSchema( matches[ 0 ].split( "," ) );
		// convert to ints
		for( var i = 0; i < inpArray.length; i++ ){
			var val = parseInt( inpArray[ i ], 10 );
			if(isNaN(val)){
				return "Sorry, couldn't load. Some elements weren't numbers!";
			}
			inpArray[ i ] = val;
		}
		if( inpArray[ 0 ] != this.schemaVersion ){
			inpArray = this.updateSchema( inpArray );
		}
		
		if(inpArray.length != this.eg[ 0 ].length){
			return "Sorry, couldn't load. Not the right number of data elements.\n\nYou passed in " + 
					inpArray.length + " but I need " + 
					this.eg[ 0 ].length + ".";
		}
		
		return inpArray;
	},
	
	addPeHandlers : function(){
		// Adds all the sliders
		var pe = this.pe;
		$("#num").slidify({ obj: pe, prop: "maxParticles", max:300 });
		$("#size").slidify({ obj: pe, prop: "size" });
		$("#sizeVar").slidify({ obj: pe, prop: "sizeRandom" });
		$("#spreadX").slidify({ obj: pe.positionRandom, prop:"x", max:200});
		$("#spreadY").slidify({ obj: pe.positionRandom, prop:"y", max:200});
		$("#speed").slidify({ obj: pe, prop:"speed", max:30 });
		$("#speedVar").slidify({ obj: pe, prop:"speedRandom", max:30 });
		$("#life").slidify({ obj: pe, prop: "lifeSpan",max:50 });
		$("#lifeVar").slidify({ obj: pe, prop: "lifeSpanRandom", max:50 });
		$("#angle").slidify({ obj: pe, prop: "angle", max: 360 });
		$("#angleVar").slidify({ obj: pe, prop: "angleRandom", max: 360 });
		$("#gravityDir").slidify({ obj: pe.gravity, prop: "x", max:10, step:0.25 });
		$("#gravitySpeed").slidify({ obj: pe.gravity, prop: "y", min:-2, max:2,step:0.25 });
		$("#sharpness").slidify({ obj: pe, prop: "sharpness", max: 99 });
		$("#sharpnessVar").slidify({ obj: pe, prop: "sharpnessRandom", max: 99 });

		$("#startR").slidify({ obj: pe.startColour, prop: 0, max:255 });
		$("#startG").slidify({ obj: pe.startColour, prop: 1, max:255 });
		$("#startB").slidify({ obj: pe.startColour, prop: 2, max:255 });
		$("#startA").slidify({ obj: pe.startColour, prop: 3, max:255 });
		$("#startRVar").slidify({ obj: pe.startColourRandom, prop: 0, max:255 });
		$("#startGVar").slidify({ obj: pe.startColourRandom, prop: 1, max:255 });
		$("#startBVar").slidify({ obj: pe.startColourRandom, prop: 2, max:255 });
		$("#startAVar").slidify({ obj: pe.startColourRandom, prop: 3, max:255 });

		$("#endR").slidify({ obj: pe.finishColour, prop: 0, max:255 });
		$("#endG").slidify({ obj: pe.finishColour, prop: 1, max:255 });
		$("#endB").slidify({ obj: pe.finishColour, prop: 2, max:255 });
		$("#endA").slidify({ obj: pe.finishColour, prop: 3, max:255 });
		$("#endRVar").slidify({ obj: pe.finishColourRandom, prop: 0, max:255 });
		$("#endGVar").slidify({ obj: pe.finishColourRandom, prop: 1, max:255 });
		$("#endBVar").slidify({ obj: pe.finishColourRandom, prop: 2, max:255 });
		$("#endAVar").slidify({ obj: pe.finishColourRandom, prop: 3, max:255 });

		$("#mode")
			.slidify({ obj: controller, prop:"blendMode", max: 3, step: 1, bind:false })
			.bind( "slide slidechange", function(e, ui){
				controller.setBlendMode( ui.value ); 
			});

		// Handle the bouncy bounce
		$("#bounce").slider({ 
			max: 15, step:0.25, value: controller.xSpeed, 
			slide: function( e,ui ){ 
				controller.xSpeed = ui.value; 
				if( ui.value > 0 ) controller.doSin = true;
			}, 
			change: function( e,ui ){
				controller.xSpeed = ui.value; 
				if( controller.xSpeed === 0 ){
					controller.doSin = false;
					controller.pe.position.x = 325;
					controller.pe.position.y = 180;
				}
			}
		});
	}
};

/* Generalises the slider creation and functionality */
(function( $ ){
	$.fn.slidify = function( options ){
		var settings = jQuery.extend({
			max: 100,
			min: 0,
			step: 1,
			bind: true,
		}, options);

		return this.each(function(){
			$(this).slider({
				value: settings.obj[ options.prop ], 
				max:options.max, 
				min: settings.min,
				step: settings.step,
				slide:function( e,ui ){ 
					if(settings.bind){
						settings.obj[ settings.prop ] = ui.value;
					}
				},
				change:function(e,ui){ 
					if( settings.bind ){
						settings.obj[ settings.prop ] = ui.value;
					}
				} 
			}).addClass( "ctrlSlider" );
		});
	};
})( jQuery );
